//====loader.es6====//

let anyInstance = null;

const defaultCacheKey = 'require-any-cache';

class AnyLoader {

	constructor(config) {
		if (anyInstance)
			return anyInstance;

		Object.defineProperties(
			this, {
				config             : {
					value     : config || {},
					readable  : true,
					enumerable: true,
					writable  : false
				},
				supportLocalStorage: {
					value     : LocalCached.supportLocalStorage,
					readable  : true,
					enumerable: true,
					writable  : false
				}
			}
		);

		anyInstance = this;
	}

	get isDebug() {
		if (!!this.config.debug) {
			if (isNaN(this.config.debug) || this.config.debug < 0)
				return 1;
			return this.config.debug;
		}
		return 0;
	}

	get isBuild() { return !!this.config.build; }

	get cacheKey() { return this.emptyStrOr(this.config.cacheKey, defaultCacheKey); }

	get patterns() { return this.isArray(this.config.patterns) ? this.config.patterns : []; }

	get hasPatterns() { return this.patterns.length <= 0; }

	get exts() { return this.config.ext || {}; }

	get plugins() { return this.config.plugins || {}; }

	get options() { return this.config.options || {}; }

	get cache() {
		return new SourceCached(this.cacheKey);
	}

	//////////////////////

	match(name) {
		let ps = this.patterns, pl = ps.length;
		let plugin = false;
		if (pl > 0) {
			for (let i = 0; i < pl; i++) {
				let p = ps[i];
				if (p.regex) {
					let regex = p.regex;
					if (this.isString(regex) && regex !== '')
						regex = new RegExp(p.regex, p.mode || null);
					if (regex instanceof RegExp) {
						let match = name.match(regex);
						if (match) {
							this.callFunc(this, p.onMatch, name, match);
							plugin = p.plugin;
							break;
						}
					}
				}
			}
		}
		if (plugin === false) {
			plugin = this.getAliasExt(this.getFileExt(name));
		}
		return this.getPlugin(plugin);
	}

	getFileExt(name) {
		var match = name.match(/\.([a-z0-9-_]+)$/i);
		if (match)
			return match[1].toLowerCase();
		return false;
	}

	getAliasExt(ext) {
		return this.exts[ext] || ext;
	}

	getPlugin(plugin) {
		return this.plugins[plugin] || undefined;
	}

	getExtOptions(ext) {
		// 加载后缀的选项时，优先加载当前的选项。
		var options = this.options || {};
		if (options[ext])
			return options[ext];
		ext = this.getAliasExt(ext);
		return options[ext] || {};
	}

	// AMD/require.js api
	load(name, req, load, config) {
		if (this.isDebug > 1)
			console.log('load', name, req.toUrl(name));
		let plugin, error = null;
		if (!this.isBuild)
			plugin = this.match(name);

		var onHandle = function (_plugin) {
			_plugin = _plugin || {};
			if (callFunc(_plugin.handle, name, req, load, config) === false)
				load.error(new Error('Invalid plugin handle in module ' + name));
		};

		switch (toString.call(plugin)) {
			case '[object Function]' :
				onHandle({handle: plugin});
				break;
			case '[object String]' :
				req([plugin], onHandle);
				break;
			//case '[object Array]' :
			//	req(handle, onHandle);
			//	break;
			case '[object Object]' :
				onHandle(plugin);
				break;
			default :
				error = new Error('Unknown handle with extension "' + ext + '"');
		}
		if (error != null)
			load.error(error);
	}

	//////////////////////

	xhr = initXhr;

	Base64 = Base64;
	LocalCached = LocalCached;
	// javascript type utils
	isUndefined = isUndefined;
	isset = isset;
	isString = isString;
	trim = trim;
	isArray = isArray;
	isObject = isObject;
	undefinedOr = undefinedOr;
	unsetOr = unsetOr;
	emptyStrOr = emptyStrOr;
	callFunc = callFunc;
	round = round;
	// json
	jsonDecode = jsonDecode;
	jsonEncode = jsonEncode;
	// diff datetime
	diffDate = diffDate;
	// others
	adjustSize = adjustSize;

	//////////////////////
}
